
// 赋值数组 ,主数据
const types = {
    obj: '[object Object]',
    array: '[object Array]'
}

export type Opts = {

    object?: {length?: number,content?: number};
    array?: {length?: number,content?: number};
    sort?: (a,b)=> number;
};


// 为 存储数据 服务，不能当做 Object.assign 使用
export class DataUtils{
    /** 持久化设置模板 */
    static readonly TEMPLATE_OPTS_STORAGE = {object: {length: 0,content: 1},array: {length: 0,content: 1}};
    
    static isObject(object){
        return Object.prototype.toString.call(object) === types.obj;
    }
    static isArray(object){
        return Object.prototype.toString.call(object) === types.array;
    }

    private static parseOpts(opts: Opts){
        if(opts === undefined){
            opts = {
                object: {length: 1,content: 1},array: {length: 1,content: 1},
            }
        }else{
            if(!opts.object){
                opts.object = {}
            }
            
            opts.object.length = opts.object.length === undefined ? 1 : opts.object.length;
            opts.object.content = opts.object.content === undefined ? 1 : opts.object.content;
            
            if(!opts.array){
                opts.array = {}
            }
            opts.array.length = opts.array.length === undefined ? 1 : opts.array.length;
            opts.array.content = opts.array.content === undefined ? 1 : opts.array.content;
        }
        return opts;
    }


    static assign(target: any,source: any,opts?: Opts){
        if(this.isArray(target)){
            return this._assignArray(target,source,opts);
        }else if(this.isObject(target)){
            return this._assign(target,source,opts);
        }
    }


    /**
     * 
     * @param target 
     * @param source 
     * @param opts 
     * -
     * - object: 对象的合并方式  0: 以目标对象数据为主，1: 以源数据为主 
     * - array:  数组的合并方式 length: [0: 长度以目标数据为主, 1: 长度以源数据为主,2: 连接两个数据],content: [0: 内容以目标数据为主,1: 内容以源数据为主]
     * @returns 
     */
     private static _assign(target: any,source: any,opts?: Opts){
        if(source === undefined){
            return target;
        }
        opts = this.parseOpts(opts);


        if(opts.object.length === 0){
            // 长度以目标数据为主
            for (const key in target) {
                if (Object.prototype.hasOwnProperty.call(target, key)) {
                    if(opts.object.content === 0){
                        // 内容以目标数据为主
                        if(this.isObject(target[key])){
                            target[key] = this._assign(target[key],source[key],opts);
                        }else if(this.isArray(target[key])){
                            target[key] = this._assignArray(target[key],source[key],opts);
                        }else{

                        }
                    }else if(opts.object.content === 1){
                        // 内容以源数据为主
                        if(this.isObject(source[key])){
                            target[key] = this._assign(target[key],source[key],opts);
                        }else if(this.isArray(source[key])){
                            target[key] = this._assignArray(target[key],source[key],opts);
                        }else{
                            target[key] = source[key] === undefined ? target[key] : source[key];
                        }
                    }
                }
            }

        }else if(opts.object.length === 1){
                for (const key in source) {
                    if (Object.prototype.hasOwnProperty.call(source, key)) {
                        if(opts.object.content === 0){
                            // 内容以目标数据为主
                            if(this.isObject(target[key])){
                                target[key] = this._assign(target[key],source[key],opts);
                            }else if(this.isArray(target[key])){
                                target[key] = this._assignArray(target[key],source[key],opts);
                            }else{
                                if(target[key] === undefined){
                                    target[key] = source[key];
                                }
                            }
                        }else if(opts.object.content === 1){
                            // 内容以源数据为主
                            if(this.isObject(source[key])){
                                target[key] = this._assign(target[key],source[key],opts);
                            }else if(this.isArray(source[key])){
                                target[key] = this._assignArray(target[key],source[key],opts);
                            }else{
                                target[key] = source[key];
                            }
                        }
                    }
                }

                for (const key in target) {
                    if((key in source) === false){
                        delete target[key];
                    }
                }
        }
        return target;
    }

    /**
     * 
     * @param target 
     * @param source 
     * @param model 
     * -
     * - object:  0: 以目标对象数据为主，1: 以源数据为主 
     * - array: 数组的合并方式 length: [0: 长度以目标数据为主, 1: 长度以源数据为主,2: 连接两个数据],content: [0: 内容以目标数据为主,1: 内容以源数据为主]
     * @returns 
     */
    private static _assignArray(target: any[],source: any[],opts?: Opts){
        
        if(source === undefined){
            return target;
        }
        opts = this.parseOpts(opts);

        if(opts.sort){
            target.sort(opts.sort);
            source.sort(opts.sort);
        }


        if(opts.array.length === 0){
            // 长度以目标数据为主
            for (let i = 0; i < target.length; i++) {
                if(opts.array.content === 0){
                    // 内容以目标数据为主
                    if(this.isObject(target[i])){
                        target[i] = this._assign(target[i],source[i],opts);
                    }else if(this.isArray(target[i])){
                        target[i] = this._assignArray(target[i],source[i],opts);
                    }else{

                    }
                }else if(opts.array.content === 1){
                    // 内容以源数据为主
                    if(this.isObject(source[i])){
                        target[i] = this._assign(target[i],source[i],opts);
                    }else if(this.isArray(source[i])){
                        target[i] = this._assignArray(target[i],source[i],opts);
                    }else{
                        target[i] = source[i] === undefined ? target[i] : source[i];
                    }
                }
            }
        }else if(opts.array.length === 1){
            // 长度以源数据为主
            for (let j = 0; j < source.length; j++) {
                if(opts.array.content === 0){
                    // 内容以目标数据为主
                    if(this.isObject(target[j])){
                        target[j] = this._assign(target[j],source[j],opts);
                    }else if(this.isArray(target[j])){
                        target[j] = this._assignArray(target[j],source[j],opts);
                    }else{
                        if(target[j] === undefined){
                            target[j] = source[j];
                        }
                    }
                }else if(opts.array.content === 1){
                    // 内容以源数据为主
                    if(this.isObject(source[j])){
                        target[j] = this._assign(target[j] || source[j],source[j],opts);
                    }else if(this.isArray(source[j])){
                        target[j] = this._assignArray(target[j] || source[j],source[j],opts);
                    }else{
                        target[j] = source[j];
                    }
                }
            }

            if(target.length > source.length){
                while (target.length > source.length) {
                    target.pop();
                }
            }
        }else if(opts.array.length === 2){
            target = target.concat(source);
        }
        return target;
    }
}
